package com.koudai.finance.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.koudai.finance.constant.SysCode;
import com.koudai.finance.constant.WebConfig;
import com.koudai.finance.dao.UserDao;
import com.koudai.finance.dao.VerifyCodeDao;
import com.koudai.finance.entity.User;
import com.koudai.finance.enums.ResultCode;
import com.koudai.finance.exception.BusinessException;
import com.koudai.finance.service.CommonService;
import com.koudai.finance.service.LoginService;
import com.koudai.finance.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.concurrent.TimeUnit;

/**
 * @Description: 登录服务
 * @author: ls
 * @Date: 2020/7/10 14:00
 */
@Slf4j
@Service
public class LoginServiceImpl implements LoginService {

    @Resource
    private UserDao userDao;

    @Resource
    private VerifyCodeDao verifyCodeDao;

    @Resource
    private CommonService commonServiceImpl;

    @Resource
    private AsyncUtils asyncUtils;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private WebConfig webConfig;

    @Resource
    private WxAuthUtil wxAuthUtil;

    /**
     * @Description: 获取短信验证码
     * @author: ls
     * @Date: 2020/7/14 19:52
     */
    @Override
    public void getVerifyCode(String phone, HttpServletRequest request) {
        // 1、校验验证码发送次数是否超过限制
        long longIp = IpUtil.getLongIp(request);
        int count = verifyCodeDao.getTodaySmsCodeCount(longIp, DateUtil.getOffsetDayStart(0, DateUtil.DATETIME_FORMAT));
        if (count >= SysCode.COUNT_SMS_CODE_LIMIT) {
            throw new BusinessException(ResultCode.COUNT_SMS_CODE_LIMIT_ERROR);
        }
        String smsCode = String.valueOf((int) ((Math.random() * 9 + 1) * 100000));
        String smsCodeSign = commonServiceImpl.getSysConfigList("smsCodeSign").get(0).getValue();
        // 3、注册平台的发送口袋网科技开头 固定的不用变
        SmsUtil.sendCrMessage(phone, smsCode, smsCodeSign);
        asyncUtils.getFuture(() -> saveSmsCode(phone, longIp, smsCode));
    }

    /**
     * @Description: 获取微信登录获取回调地址 1-静默 2-普通
     * snsapi_userinfo非静默 snsapi_base静默授权
     * @author: ls
     * @Date: 2020/7/10 14:19
     */
    @Override
    public String getWxAuthUrl(String redirectUrl, String type) throws IOException {
        String scope = "snsapi_userinfo";
        if (StringUtils.equals(type, "1")) {
            scope = "snsapi_base";
        }
        return "https://open.weixin.qq.com/connect/oauth2/authorize" +
                "?appid=" + webConfig.getWxAppId() +
                "&redirect_uri=" + URLEncoder.encode(redirectUrl, "UTF-8") +
                "&response_type=code&scope=" + scope + "&state=STATE#wechat_redirect";
    }

    /**
     * @Description: 授权获取用户openId
     * @author: ls
     * @Date: 2020/7/10 14:35
     */
    @Override
    public String authWxCallBack(String code, HttpServletResponse response) {
        JSONObject tokenJson = wxAuthUtil.getPageAccessToken(code);
        String openId = tokenJson.getString("openid");
        if (StringUtils.isBlank(openId)) {
            throw new BusinessException(ResultCode.USER_NOT_LOGGED_IN);
        }
        // 1、判断用户是否存在
        Integer userId = userDao.getUserIdByOpenId(openId);
        if (userId != null) {
            asyncUtils.getFuture(() -> updateWxInfo(userId, openId));
            String token = JwtTokenUtil.getExpToken(userId);
            response.setHeader("token", token);
        }
        return openId;
    }

    /**
     * @Description: 更新用户信息
     * @Author ls
     * @Date 2022/02/14 15:06
     */
    private void updateWxInfo(Integer userId, String openId) {
        User user = getWxInfo(openId);
        user.setId(userId);
        userDao.updateUserById(user);
        commonServiceImpl.delUserCache(userId);
    }

    /**
     * @Description: 获取用户的wx基本信息
     * @Author ls
     * @Date 2022/02/14 15:06
     */
    private User getWxInfo(String openId) {
        if (StringUtils.isBlank(openId)) {
            throw new BusinessException(ResultCode.USER_NOT_LOGGED_IN);
        }
        JSONObject jsonObject = wxAuthUtil.getPageUserInfo(openId);
        JSONObject userBase = wxAuthUtil.getUserBaseInfo(openId);
        String nickname = StringUtils.isBlank(jsonObject.getString("nickname")) ? "合伙人" : jsonObject.getString("nickname");
        String headImgUrl = jsonObject.getString("headimgurl");
        Integer subscribe = userBase.getInteger("subscribe");
        return User.builder().openId(openId).nickname(nickname).headImgUrl(headImgUrl).subscribe(subscribe).build();
    }

    /**
     * @Description: 用户注册
     * @Author ls
     * @Date 2022/02/14 15:06
     */
    @Override
    public User register(String phone, String smsCode, String openId, HttpServletResponse response) {
        // 1、校验短信验证码
        if (StringUtils.isNotBlank(smsCode)) {
            commonServiceImpl.checkSmsCode(phone, smsCode);
        }
        // 2、获取用户的基本信息
        User user = getWxInfo(openId);
        // 3、判断用户是否已经注册 已注册则更新用户信息
        Integer id = userDao.checkUserExist(phone);
        if (id != null) {
            user.setId(id);
            userDao.updateUserById(user);
            response.setHeader("token", JwtTokenUtil.getExpToken(id));
            commonServiceImpl.delUserCache(id);
            return commonServiceImpl.getUserInfo(id);
        }
        user.setPhone(phone);
        userDao.saveUser(user);
        response.setHeader("token", JwtTokenUtil.getExpToken(user.getId()));
        return commonServiceImpl.getUserInfo(user.getId());
    }

    /**
     * @Description: 保存验证码到数据库和redis
     * @author: ls
     * @Date: 2020/7/14 20:03
     */
    private void saveSmsCode(String phone, long ip, String smsCode) {
        verifyCodeDao.save(phone, ip, smsCode);
        String key = String.format("%s%s", SysCode.REDIS_KEY_SMS_CODE, phone);
        redisUtil.set(key, smsCode, 5, TimeUnit.MINUTES);
    }

}